package cn.lg.soar.system.biz.modules.auth.client;

import cn.lg.soar.common.util.current.UserContext;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.core.annotations.ApiClient;
import cn.lg.soar.database.annotations.DataScopeIgnore;
import cn.lg.soar.database.datascope.DataScopeUtils;
import cn.lg.soar.database.datascope.Filter;
import cn.lg.soar.database.datascope.IDataPermissionService;
import cn.lg.soar.database.enums.ProvideTypeEnum;
import cn.lg.soar.system.api.constant.ModuleConst;
import cn.lg.soar.system.biz.modules.auth.model.DataRuleItemDTO;
import cn.lg.soar.system.biz.modules.auth.service.IDataRuleProvideService;
import cn.lg.soar.system.biz.modules.auth.service.IDataScopeService;
import cn.lg.soar.system.biz.modules.auth.service.IUserService;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Primary;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luguoxiang
 * @date 2022/1/3
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@ConditionalOnProperty(name = "lg.database.enabled-data-permission", havingValue = "true", matchIfMissing = true)
@Primary
@Hidden
@ApiClient("boot")
@RestController
@RequestMapping(ModuleConst.CLIENT_PATH + "/datapermission")
public class DataPermissionApiClient implements IDataPermissionService {

    @Autowired
    private IUserService userService;
    @Autowired
    private IDataScopeService dataScopeService;
    @Autowired
    private IDataRuleProvideService dataRuleProvideService;

    @DataScopeIgnore
    @GetMapping("dataScopes")
    @Override
    public List<List<Filter>> dataScopes(@RequestParam(name = "resourceCode") String resourceCode) {
        Map<Long, List<DataRuleItemDTO>> resourceRuleMap = dataScopeService.getResourceRuleMap(resourceCode);
        if (DataUtil.isEmpty(resourceRuleMap)) {
            // 没配置数据权限，可访问所有数据
            return DataScopeUtils.ALL_DATA_SCOPE;
        }
        Long userId = UserContext.getUserId();
        if (userService.isSuperAdministrator(userId)) {
            // 超级管理员，可访问所有数据
            return DataScopeUtils.ALL_DATA_SCOPE;
        }
        // 查找所有角色数据权限
        List<Long> roleIds = userService.getUserCurrentAllRoleIds(userId);
        Set<List<DataRuleItemDTO>> set;
        if (DataUtil.isValuable(roleIds)) {
            set = roleIds.stream()
                    .map(resourceRuleMap::get)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
        } else {
            set = null;
        }
        if (DataUtil.isEmpty(set)) {
            // 没匹配到，取缺省规则
            List<DataRuleItemDTO> items = resourceRuleMap.get(0L);
            if (items == null) {
                // 没有默认规则，则用户没有数据权限
                return DataScopeUtils.NOT_DATA_SCOPE;
            }
            set = Collections.singleton(items);
        }
        // 处理规则
        return set.stream()
                .map(ls -> ls.stream()
                        .map(x -> {
                            // 保证每次调用都是最新值，避免缓存问题
                            String columnValue = x.getColumnValue();
                            ProvideTypeEnum provideType = x.getProvideType();
                            Object value = dataRuleProvideService.getColumnValue(provideType, columnValue);
                            Filter filter = new Filter();
                            filter.setColumnName(x.getColumnName());
                            filter.setExpression(x.getExpression());
                            filter.setColumnValue(value);
                            filter.setSpliceType(x.getSpliceType());
                            return filter;
                        })
                        .collect(Collectors.toList())
                ).collect(Collectors.toList());
    }

}
